import {
    _decorator,
    Component,
    instantiate,
    LabelComponent,
    LayoutComponent,
    Node,
    NodeEventType,
    Prefab,
    Size,
    sys,
    UITransformComponent,
    v3,
    v2,
    Vec3,
    Event,
    Vec2,
    EventTouch,
    tween,
    Tween,
    director, AudioClip,
    Label, Sprite,
    Canvas,
    assetManager, ImageAsset, SpriteFrame, Texture2D, resources,
    UITransform,
    Color,
    Quat,
    WidgetComponent
} from 'cc';
import {MathUtil} from "db://assets/scripts/MathUtil";
import {Item} from "db://assets/scripts/Item";
import {WxUser} from "db://assets/scripts/dto/WxUser";
import {Vec3DTO, Vec3StatusDTO} from "db://assets/scripts/dto/Vec3DTO";
import {Modal} from "db://assets/scripts/component/Modal";
import {AudioMgr} from "db://assets/scripts/component/AudioMgr";
import {RoofInfoDTO} from "db://assets/scripts/dto/RoofInfoDTO";
import {ClientInfoDTO} from "db://assets/scripts/dto/ClientInfoDTO";
import {SocketMessage} from "db://assets/scripts/dto/SocketMessage";
import {WebsocketMgr} from "db://assets/scripts/component/WebsocketMgr";
import {SocketLogicInterface} from "db://assets/scripts/interface/SocketLogicInterface";
import {
    DirectionInfo, propTypeInfo, PropTypeOneEnum, PropTypeThreeEnum, PropTypeTwoEnum
} from "db://assets/scripts/consts/PropTypeEnum";
import {Prop} from "db://assets/scripts/dto/Prop";
import {DateTimeUtil} from "db://assets/scripts/util/DateTimeUtil";
import {PropItemScript} from "db://assets/scripts/component/PropItemScript";
import {UsePropDTO} from "db://assets/scripts/dto/UsePropDTO";
import {
    Game2048LevelEnum,
    getBeforeLevel,
    getNextLevel,
    levelEnumInfo,
    LevelInfo
} from "db://assets/scripts/consts/Game2048LevelEnum";
import {Stat} from "db://assets/scripts/component/Stat";
import {Lv2048Tg} from "db://assets/scripts/component/Lv2048Tg";
import {post} from "db://assets/scripts/config/Api";
import {Palette} from "db://assets/scripts/component/Palette";
import {ColorUtil} from "db://assets/scripts/util/ColorUtil";


const {ccclass, property} = _decorator;

class ItemPosition {
    position: Vec3;
    item: Node;
    status: Vec3StatusDTO[] = [];

    constructor(position: Vec3, item?: Node) {
        this.position = position;
        this.item = item;
    }
}

@ccclass('GameMany2048')
export class GameMany2048 extends Component implements SocketLogicInterface {


    @property(Node)
    gameMain: Node = null!;

    @property(Node)
    overGame: Node = null!;

    userData: ClientInfoDTO = null;
    userDataTwo: ClientInfoDTO = null;


    @property(LabelComponent)
    scoreLabel: LabelComponent = null!;


    @property(LabelComponent)
    previewScoreLabel: LabelComponent = null!;

    @property(LabelComponent)
    backLabel: LabelComponent = null!;

    @property(Node)
    ndParend: Node = null!;

    @property(Node)
    userStatusLabel: Node = null!;

    @property(Node)
    userStatusTwoLabel: Node = null!;

    @property(Node)
    squereParent: Node = null!;

    @property(Node)
    ndParendTwo: Node = null!;

    @property(Node)
    squereParentTwo: Node = null!;

    ndLayoutComponentTwo: LayoutComponent = null!;

    @property(Prefab)
    itemBgPrefab: Prefab = null!;

    @property(Prefab)
    itemPrefab: Prefab = null!;

    ndLayoutComponent: LayoutComponent = null!;

    squareArray: ItemPosition [][] = null;
    squareTwoArray: ItemPosition [][] = null;


    @property(Node)
    canvas: Node = null!;


    touchStartPosition: Vec2 = null;
    touchEndPosition: Vec2 = null;

    isGame: boolean = false;

    isGameOver: boolean = false;

    userInfo: WxUser;
    currentScore: number = 0;

    // 对方增加分数
    opponentCurrentScore: number = 0;

    @property(AudioClip)
    bgMusic: AudioClip = null!;

    @property(AudioClip)
    sliderMusic: AudioClip = null;

    @property(AudioClip)
    mergeMusic: AudioClip = null;

    roomInfo: RoofInfoDTO = null;

    squareWh: number;
    squareWh2: number;

    @property(Label)
    userName: Label = null!;

    @property(Label)
    previewUserName: Label = null!;


    @property(Sprite)
    userHead: Sprite = null!;

    @property(Sprite)
    previewUserHead: Sprite = null!;

    @property(Node)
    office: Node = null!;

    @property(Node)
    previewOffice: Node = null!;
    @property(Node)
    gamePending: Node = null!;
    @property(Label)
    gamePendingText: Label = null!;

    @property(Node)
    markNode: Node = null!;


    @property(Label)
    startRemain: Label = null!;
    @property(Label)
    remainValue: Label = null!;

    propSpriteMap: Map<number, SpriteFrame> = new Map();


    @property(Node)
    propPanel: Node = null!;

    @property(Prefab)
    propItem: Prefab = null!;

    @property(Node)
    chessboard: Node = null!;

    @property(Node)
    previewChessboard: Node = null!;

    opponentProp: UsePropDTO[] = [];
    isTouch: boolean = false;


    currentPropItem: PropItemScript = null;

    @property(Node)
    propLayout: Node = null!;
    @property(Node)
    previewPropLayout: Node = null!;

    isProtectiveCover: boolean = false;

    @property(Node)
    propDescPanel: Node = null!;

    starInterval: number;

    isNotTouch: boolean = false;

    @property(SpriteFrame)
    starNull: SpriteFrame = null!;

    @property(SpriteFrame)
    starBold: SpriteFrame = null!;


    @property(SpriteFrame)
    star: SpriteFrame = null!;

    @property(Node)
    starIContail: Node = null!;

    @property(Prefab)
    starPrefab: Prefab = null!;


    @property(Lv2048Tg)
    userLvNode: Lv2048Tg = null!;

    @property(Lv2048Tg)
    previewUserLvNode: Lv2048Tg = null!;

    @property(Lv2048Tg)
    winUserLvNode: Lv2048Tg = null!;

    @property(Node)
    tyro: Node = null!;

    @property(Palette)
    bgPalette: Palette = null!;


    async start() {
        this.initPanel();
        this.ndLayoutComponent = this.ndParend.getComponent(LayoutComponent);
        this.ndLayoutComponentTwo = this.ndParendTwo.getComponent(LayoutComponent);
        this.addTouch();
        this.userInfo = JSON.parse(localStorage.getItem('userInfo'));
        if (this.userInfo.tyro === 1) {
            // 新手引导面包激活
            this.tyro.active = true;
        }
        this.roomInfo = JSON.parse(localStorage.getItem('roofInfo'));
        this.startRemainStart();
        this.remainStart();
        this.subscription();
        await this.startGame();
        this.downProp();
        this.initProp();


    }

    update(deltaTime: number) {
        // 道具相关逻辑

    }


    oppentIsUseProp: boolean;

    async opponentPropUseCallBack() {
        try {
            if (this.opponentProp.length === 0
                || this.isTouch) {
                return;
            }
            this.scheduleOnce(async () => {
                if (this.oppentIsUseProp) {
                    return;
                }
                if (this.opponentProp.length === 0) {
                    return;
                }
                this.oppentIsUseProp = true;
                let usePropDTO = this.opponentProp.pop();


                switch (usePropDTO.prop.type) {
                    case 50: {
                        this.opponentUseBoom(usePropDTO);
                        break;
                    }
                    case 51: {
                        this.opponentUseFrozen(usePropDTO);
                        break;
                    }
                    case 52: {
                        this.opponentUseFog(usePropDTO);
                        break;
                    }
                    case 53: {
                        this.opponentUseProtectiveCover(usePropDTO);
                        break;
                    }
                    case 100: {
                        this.opponentUseReversed(usePropDTO);
                        break;
                    }
                    case 101: {
                        this.opponentUseCurse(usePropDTO);
                        break;
                    }
                    case 150: {
                        this.opponentUseLuckyCubes(usePropDTO);
                        break;
                    }
                    case 151: {
                        this.opponentUseFormulate(usePropDTO);
                        break;
                    }
                }
                this.oppentIsUseProp = false;
            }, 0);

        } catch (e) {
            console.log("对手使用道具，异常")
            console.error(e)
        }
    }

    /**
     * 策反
     * @param usePropDTO
     * @private
     */
    private opponentUseFormulate(usePropDTO: UsePropDTO) {
        // 随机找到自己一个数字
        let itemPosition: ItemPosition = this.randomSquare(1);

        if (itemPosition != null) {
            this.addStatus(itemPosition.status, usePropDTO.prop.type, 999);
        }

        let message: SocketMessage = new SocketMessage();
        message.event = "usePropSuccess";
        if (itemPosition) {
            usePropDTO.selectEnemyPosition = [itemPosition.position];
            usePropDTO.selectEnemyPosition[0].status = itemPosition.status;
        }

        if (itemPosition == null || itemPosition.item == null) {
            usePropDTO.selectEnemyPosition = [];
            message.data = usePropDTO;
            WebsocketMgr.inst.sendMessage(message);
            return;
        } else {
            message.data = usePropDTO;
            WebsocketMgr.inst.sendMessage(message);
        }
        let prop: Node = this.addPropStatus(
            itemPosition,
            usePropDTO.prop.type,
            itemPosition.item,
            this.squareWh
        );
        prop.children[0].getComponent(Sprite).color = new Color(255, 255, 255, 122)
    }

    private opponentUseLuckyCubes(usePropDTO: UsePropDTO) {
        let message: SocketMessage = new SocketMessage();
        message.event = "usePropSuccess";
        // 为了销毁道具，传false
        usePropDTO.success = false;
        message.data = usePropDTO;
        WebsocketMgr.inst.sendMessage(message);

        let vec3DTO = usePropDTO.selectMePosition.pop();
        if (vec3DTO) {
            this.mergeSquare2(this.squareTwoArray, this.userDataTwo, vec3DTO.x, vec3DTO.y);
        }
    }

    private opponentUseCurse(usePropDTO: UsePropDTO) {
        let itemPosition: ItemPosition = this.randomSquare(1);
        if (itemPosition != null) {
            this.addStatus(itemPosition.status, usePropDTO.prop.type, 999);
        }
        let message: SocketMessage = new SocketMessage();
        message.event = "usePropSuccess";
        if (itemPosition) {
            usePropDTO.selectEnemyPosition = [itemPosition.position];
            usePropDTO.selectEnemyPosition[0].status = itemPosition.status;
        }

        if (itemPosition == null || !itemPosition.item) {
            usePropDTO.selectEnemyPosition = [];
            message.data = usePropDTO;
            WebsocketMgr.inst.sendMessage(message);
            return;
        } else {
            message.data = usePropDTO;
            WebsocketMgr.inst.sendMessage(message);
        }
        this.addPropStatus(
            itemPosition,
            usePropDTO.prop.type,
            itemPosition.item,
            this.squareWh
        );


    }

    private opponentUseReversed(usePropDTO: UsePropDTO): Promise<any> {

        this.isNotTouch = true;
        // let rotaryCount = MathUtil.randomMax(3);
        let rotaryCount = 1;

        for (let i = 0; i < rotaryCount; i++) {
            this.squareArray = this.rotateMatrixClockwise(this.squareArray);
        }

        let transArray = this.transArray();

        let message: SocketMessage = new SocketMessage();
        message.event = "usePropSuccess";
        usePropDTO.current = transArray;
        usePropDTO.rotaryCount = rotaryCount;
        message.data = usePropDTO;
        WebsocketMgr.inst.sendMessage(message);
        let angle = this.squereParent.parent.angle;
        return new Promise<any>((resolve, reject) => {
            tween(this.squereParent.parent)
                .to(0.5, {angle: (-90 * (rotaryCount)) + angle}, {easing: "sineIn"})
                .call(() => {
                    this.isNotTouch = false;
                    resolve(null);
                })
                .start()
        });
    }

    private opponentUseProtectiveCover(usePropDTO: UsePropDTO) {
        let message: SocketMessage = new SocketMessage();
        message.event = "usePropSuccess";
        usePropDTO.success = false;
        message.data = usePropDTO;
        WebsocketMgr.inst.sendMessage(message);
        // 释放保护罩
        let prop: Node = this.addPropStatus(
            null,
            usePropDTO.prop.type,
            this.previewPropLayout,
            this.squareWh2 * 4
        );
        prop.children[0].getComponent(Sprite).color = new Color(48, 240, 201, 100);

        setTimeout(() => {
            prop.destroy();
        }, 300)
    }

    private opponentUseFog(usePropDTO: UsePropDTO) {
        let message: SocketMessage = new SocketMessage();
        message.event = "usePropSuccess";
        message.data = usePropDTO;
        WebsocketMgr.inst.sendMessage(message);
        // 释放迷雾
        let prop: Node = this.addPropStatus(
            null,
            usePropDTO.prop.type,
            this.propLayout,
            this.squareWh * 4
        );
        setTimeout(() => {
            prop.destroy();
        }, 3000)
    }

    /**
     * 冻结
     * @param usePropDTO
     * @private
     */
    private opponentUseFrozen(usePropDTO: UsePropDTO) {
        try {
            // 随机找到一个数字进行冻结
            let itemPosition: ItemPosition = this.randomSquare(1);
            if (itemPosition != null) {
                this.addStatus(itemPosition.status, usePropDTO.prop.type, 2);

            }
            let message: SocketMessage = new SocketMessage();
            message.event = "usePropSuccess";
            if (itemPosition && itemPosition.item) {
                usePropDTO.selectEnemyPosition = [itemPosition.position];
                usePropDTO.selectEnemyPosition[0].status = itemPosition.status;
            }
            message.data = usePropDTO;

            WebsocketMgr.inst.sendMessage(message);
            if (itemPosition == null || !itemPosition.item) {
                return;
            }
            this.addPropStatus(
                itemPosition,
                usePropDTO.prop.type,
                itemPosition.item,
                this.squareWh
            );


        } catch (e) {
            console.error(e);
        }
    }

    /**
     * 在棋盘随机有数字的位置生成一个炸弹,炸掉数字
     * @param usePropDTO
     * @private
     */
    private opponentUseBoom(usePropDTO: UsePropDTO): Promise<any> {
        // 找到数字
        try {
            let itemPosition: ItemPosition = this.randomSquare(1);


            // 发送炸弹成功信息
            let message: SocketMessage = new SocketMessage();
            message.event = "usePropSuccess";
            if (itemPosition) {

                usePropDTO.selectEnemyPosition = [itemPosition.position];
            }


            if (itemPosition == null || itemPosition.item == null) {
                message.data = usePropDTO;
                WebsocketMgr.inst.sendMessage(message);
                return;
            }

            // 炸弹动画,直接在固体格子上播放动画
            //初始化炸弹
            let prefab: Node = this.addPropStatus(
                itemPosition,
                usePropDTO.prop.type,
                this.propLayout,
                this.squareWh
            );
            prefab.scale = v3(0.6, 0.6, 0.6);


            return new Promise<any>((resolve, reject) => {
                tween(prefab)
                    .to(0.5, {scale: v3(1.6, 1.6, 1.6)}, {easing: "sineIn"})
                    .call(() => {
                        prefab.destroy();

                        // 爆炸完看看还存在吗,存在销毁,不存在说明已经划走,不销毁
                        if (itemPosition.item) {
                            console.log("没有逃过，炸掉")
                            let score = itemPosition.position.z;
                            itemPosition.position.z = 0;
                            itemPosition.status = [];
                            itemPosition.item.destroy();
                            itemPosition.item = null;
                            message.data = usePropDTO;
                            WebsocketMgr.inst.sendMessage(message);
                            this.userData.score -= score;
                            this.updateView();

                        } else {
                            console.log("躲过一劫")
                            // 躲过一劫
                            usePropDTO.selectEnemyPosition = [];
                            message.data = usePropDTO;
                            WebsocketMgr.inst.sendMessage(message);
                        }
                        // 销毁物体
                        resolve(null);
                    })
                    .start()
            });
        } catch (e) {
            console.error(e);
        }
    }

    private enemyPropSuccess(message: SocketMessage) {
        let usePropDTO: UsePropDTO = message.data as UsePropDTO;

        let temp = this.currentPropItem;
        this.currentPropItem = null;

        for (let i = 0; i < this.userData.props.length; i++) {
            let propItem: Prop = this.userData.props[i];
            if (propItem.id === temp.id) {
                this.userData.props.splice(i, 1);
            }
        }

        if (usePropDTO.success === false) {
            // 道具直接销毁
            temp.node.destroy();
            return;
        }

        switch (usePropDTO.prop.type) {
            case 50: {
                this.useBoomSuccessCall(usePropDTO, temp);
                break;
            }
            case 51: {
                this.useFrozenSuccessCall(usePropDTO, temp);
                break;
            }
            case 52: {
                this.useFogSuccessCall(usePropDTO, temp);

                break;
            }
            case 53: {
                //  this.useProtectiveCoverSuccessCall(usePropDTO, temp);
                break;
            }
            case 100: {
                this.useReversedSuccessCall(usePropDTO, temp);
                break;
            }
            case 101: {
                this.useCurseSuccessCall(usePropDTO, temp);
                break;
            }
            case 151: {
                this.useFormulateSuccessCall(usePropDTO, temp);
                break;
            }
        }
    }

    private useFormulateSuccessCall(usePropDTO: UsePropDTO, temp: PropItemScript) {
        if (usePropDTO.selectEnemyPosition) {
            let itemPosition: ItemPosition = this.squareTwoArray[usePropDTO.selectEnemyPosition[0].x][usePropDTO.selectEnemyPosition[0].y];
            this.addStatus(itemPosition.status, usePropDTO.prop.type, 999)

            this.addPropStatus(
                itemPosition,
                usePropDTO.prop.type,
                itemPosition.item,
                this.squareWh2,
                temp.node
            );
            temp.node.children[0].getComponent(Sprite).color = new Color(255, 255, 255, 122)

        } else {
            temp.node.destroy();
        }

    }

    private useCurseSuccessCall(usePropDTO: UsePropDTO, temp: PropItemScript) {
        if (usePropDTO.selectEnemyPosition) {
            let itemPosition: ItemPosition = this.squareTwoArray[usePropDTO.selectEnemyPosition[0].x][usePropDTO.selectEnemyPosition[0].y];
            this.addStatus(itemPosition.status, usePropDTO.prop.type, 999)
            this.addPropStatus(
                itemPosition,
                usePropDTO.prop.type,
                itemPosition.item,
                this.squareWh2,
                temp.node
            );
        } else {
            temp.node.destroy();
        }
    }


    private useReversedSuccessCall(usePropDTO: UsePropDTO, temp: PropItemScript) {
        //数据复制
        temp.node.destroy();
        let angle = this.squereParentTwo.parent.angle;
        tween(this.squereParentTwo.parent)
            .to(0.5, {angle: (-90 * 1) + angle}, {easing: "sineIn"})
            .call(() => {
                if (usePropDTO.current) {
                    this.updatePreviewSquare(usePropDTO.current);
                    this.userDataTwo.before = this.userDataTwo.current;
                    this.userDataTwo.current = usePropDTO.current;
                }


            })
            .start();

    }

    /*private useProtectiveCoverSuccessCall(usePropDTO: UsePropDTO, temp: PropItemScript) {
        // 释放保护罩
        let prop: Node = this.addPropStatus(
            null,
            usePropDTO.prop.type,
            this.propLayout,
            this.squareWh * 4,
            temp.node
        );
        this.isProtectiveCover = true;
        prop.children[0].getComponent(Sprite).color = new Color(48, 240, 201, 100);
        setTimeout(() => {
            prop.destroy();
            this.isProtectiveCover = false;
        }, 5000)
    }*/

    private useFogSuccessCall(usePropDTO: UsePropDTO, temp: PropItemScript) {
        // 释放迷雾
        let prop: Node = this.addPropStatus(
            null,
            usePropDTO.prop.type,
            this.previewPropLayout,
            this.squareWh2 * 4,
            temp.node
        );
        setTimeout(() => {
            prop.destroy();
        }, 3000)
    }

    private useFrozenSuccessCall(usePropDTO: UsePropDTO, temp: PropItemScript) {
        if (usePropDTO.selectEnemyPosition) {
            let itemPosition: ItemPosition = this.squareTwoArray[usePropDTO.selectEnemyPosition[0].x][usePropDTO.selectEnemyPosition[0].y];
            this.addStatus(itemPosition.status, usePropDTO.prop.type, 2)

            this.addPropStatus(
                itemPosition,
                usePropDTO.prop.type,
                itemPosition.item,
                this.squareWh2,
                temp.node
            );
        } else {
            temp.node.destroy();
        }

    }

    private useBoomSuccessCall(usePropDTO: UsePropDTO, temp: PropItemScript) {
        if (usePropDTO.selectEnemyPosition) {

            let itemPosition: ItemPosition = this.squareTwoArray[usePropDTO.selectEnemyPosition[0].x][usePropDTO.selectEnemyPosition[0].y];
            this.addPropStatus(
                itemPosition,
                usePropDTO.prop.type,
                this.previewPropLayout,
                this.squareWh2,
                temp.node
            );
            temp.node.scale = v3(0.6, 0.6, 0.6);
            tween(temp.node)
                .to(0.5, {scale: v3(1.6, 1.6, 1.6)}, {easing: "sineIn"})
                .call(() => {
                    temp.node.destroy();
                    // 销毁物体
                    this.userDataTwo.score -= itemPosition.position.z;
                    this.updatePreviewView();
                    itemPosition.position.z = 0;
                    if (itemPosition.item) {
                        itemPosition.item.destroy();
                        itemPosition.item = null;
                    } else {
                        console.log("逃过没有炸掉")
                    }

                })
                .start()

        } else {
            console.log("炸弹爆炸")
            /*   let canvasLocalPos = temp.node.parent.getComponent(UITransform)!.convertToNodeSpaceAR(bWorldPos);
               let bWorldPos = this.squereParentTwo.parent.getComponent(UITransform).convertToWorldSpaceAR(this.previewChessboard.position);
             */

            const targetWorldPos = this.previewPropLayout.getComponent(UITransform).convertToWorldSpaceAR(v3(0, 0, 0));
            const targetLocalPos = temp.node.parent.getComponent(UITransform).convertToNodeSpaceAR(targetWorldPos);


            tween(temp.node).to(0.3, {
                position: targetLocalPos,
            }, {easing: "linear"})
                .call(() => {

                    tween(temp.node)
                        .to(0.5, {scale: v3(1.6, 1.6, 1.6)}, {easing: "sineIn"})
                        .call(() => {
                            temp.node.destroy();
                        })
                        .start();
                }).start();
        }

    }

    /**
     * 随机棋盘一个格子
     * @param type 1:有数字的 2：没有
     * @private
     */
    private randomSquare(type: number): ItemPosition {
        // 先把有数字的放在一起
        let squareArrayNotNull: ItemPosition[] = [];
        for (let i = 0; i < this.squareArray.length; i++) {

            for (let j = 0; j < this.squareArray[i].length; j++) {
                let squareArrayElementElement = this.squareArray[i][j];
                if (squareArrayElementElement.item != null && type === 1) {
                    squareArrayNotNull.push(squareArrayElementElement);
                } else if (squareArrayElementElement.item == null && type === 2) {
                    squareArrayNotNull.push(squareArrayElementElement);
                }
            }
        }
        return MathUtil.randomArray(squareArrayNotNull);
    }

    private startRemainStart() {
        // 倒计时
        let remaining = this.getRemaining(this.roomInfo.startDateTime);
        this.startRemain.string = remaining + "";
        // 倒计时存在
        if (remaining > 0) {
            this.startRemain.node.active = true;
            this.markNode.active = true;
            this.starInterval = setInterval(() => {
                remaining = this.getRemaining(this.roomInfo.startDateTime);
                this.startRemain.string = remaining + "";
                if (remaining <= 0) {
                    this.startRemain.node.active = false;
                    this.markNode.active = false;
                    this.isGame = true;
                    this.remainStart();
                    clearInterval(this.starInterval)
                }
            }, 1000)
        }
    }

    remainStartInterval: number;

    private remainStart() {
        // 倒计时
        let remaining = this.getRemaining(this.roomInfo.endDateTime);
        if (!this.markNode.active) {
            this.remainValue.string = remaining + "";
        }
        // 倒计时存在
        this.remainStartInterval = setInterval(() => {
            if (!this.markNode) {
                clearInterval(this.remainStartInterval);
                return;
            }
            this.opponentPropUseCallBack();
            if (this.markNode.active) {
                return;
            }
            if (this.isGameOver) {
                clearInterval(this.remainStartInterval);
                return;
            }

            remaining = this.getRemaining(this.roomInfo.endDateTime);

            this.setColor(remaining);

            this.remainValue.string = remaining + "";
            if (remaining <= 0) {
                clearInterval(this.remainStartInterval)
            }
        }, 1000)

    }


    private addTouch() {
        this.canvas.on(NodeEventType.TOUCH_START, this.touchStart,  this);
        this.canvas.on(NodeEventType.TOUCH_MOVE, this.touchMove,  this);
        this.canvas.on(NodeEventType.TOUCH_CANCEL, this.touchCancel, this);
        this.canvas.on(NodeEventType.TOUCH_END, this.touchEnd, this);
    }

    private touchStart(event: EventTouch) {
        // 新手引导面板被激活
        if (this.tyro.active) {
            this.tyro.active = false;
            post("/wx/setTyro")
            this.userInfo.tyro = 0;
            sys.localStorage.setItem("userInfo", JSON.stringify(this.userInfo));
        }

        this.closePropDesc();
        if (!this.isGame) return;

        if (this.isGameOver) return;

        if (this.isNotTouch) return;

        // 重连中
        if (WebsocketMgr.inst.isOnline === -1) return;


        this.touchStartPosition = event.getLocation();
    }

    private touchMove(event: EventTouch) {

    }

    private touchCancel(event: EventTouch) {
       // this.closePropDesc();
        this.touchEnd(event);
    }

    private touchEnd(event: EventTouch) {
        this.closePropDesc();


        if (!this.isGame) return;

        if (this.isGameOver) return;

        if (this.isNotTouch) return;

        // 重连中
        if (WebsocketMgr.inst.isOnline === -1) return;

        this.touchEndPosition = event.getLocation();

        let offsetX = this.touchEndPosition.x - this.touchStartPosition.x;
        let offsetY = this.touchEndPosition.y - this.touchStartPosition.y;

        if (Math.abs(offsetX) < 5
            && Math.abs(offsetY) < 5) {
            return;
        }

        this.isTouch = true;

        // x轴滑动
        if (Math.abs(offsetX) > Math.abs(offsetY)) {
            if (offsetX > 0) {
                // 右移
                this.moveSquare("right")
            } else {
                // 左移
                this.moveSquare("left")
            }
        } else {
            // y轴滑动
            if (offsetY > 0) {
                // 上划
                this.moveSquare("up")
            } else {
                // 下划
                this.moveSquare("down")
            }
        }

        this.isTouch = false;
    }

    public moveSquare(type: string) {
        this.currentScore = 0;
        this.opponentCurrentScore = 0;
        // this.squareArrayHistory.push(this.copyArray());
        // 记录当前记录
        let isMove: boolean = false;
        let direction = "";
        switch (type) {
            case "left":
                console.log("左移");
                direction = "left";
                isMove = this.moveLeft();
                break;
            case "right":
                console.log("右移");
                direction = "right";
                isMove = this.moveRight();
                break;
            case "up":
                console.log("上移");
                direction = "up";
                isMove = this.moveUp();
                break;
            case "down":
                console.log("下移");
                direction = "down";
                isMove = this.moveDown();
                break;
        }
        if (isMove) {
            AudioMgr.inst.playOneShot(this.sliderMusic);
            this.generateRandom();
            this.setScore(this.currentScore, this.opponentCurrentScore, direction);
            this.currentScore = 0;
            this.opponentCurrentScore = 0;
        }
        // 判断是否游戏结束
        // 获取所有等于0的位置

        let isGameOver: boolean = true;
        breakIsGameOVer:
            for (let i = 0; i < this.squareArray.length; i++) {
                // 每一列的长度
                const columnLength = this.squareArray[i].length;
                // 判断后面是否有空格
                for (let j = 0; j < columnLength; j++) {
                    if (this.squareArray[i][j]?.position.z === 0) {
                        isGameOver = false;
                        break breakIsGameOVer;
                    }
                    if (
                        this.isContains(this.squareArray[i][j]?.status, [51, 101])
                    ) {
                        continue;
                    }
                    if (this.squareArray[i][j]?.position.z
                        === this.squareArray?.[i + 1]?.[j]?.position?.z
                        && !this.isContains(this.squareArray[i + 1][j]?.status, [51, 101])
                    ) {
                        isGameOver = false;
                        break breakIsGameOVer;
                    }
                    if (this.squareArray[i][j]?.position.z
                        === this.squareArray?.[i - 1]?.[j]?.position?.z
                        && !this.isContains(this.squareArray[i - 1][j]?.status, [51, 101])
                    ) {
                        isGameOver = false;
                        break breakIsGameOVer;
                    }
                    if (this.squareArray[i][j]?.position.z
                        === this.squareArray?.[i]?.[j + 1]?.position?.z
                        && !this.isContains(this.squareArray[i][j + 1]?.status, [51, 101])
                    ) {
                        isGameOver = false;
                        break breakIsGameOVer;
                    }
                    if (this.squareArray[i][j]?.position.z
                        === this.squareArray?.[i]?.[j - 1]?.position?.z
                        && !this.isContains(this.squareArray[i][j - 1]?.status, [51, 101])
                    ) {
                        isGameOver = false;
                        break breakIsGameOVer;
                    }
                }
            }
        if (isGameOver) {
            //   this.overGame.active = true;
            this.gameOver()
        }
    };


    /**
     * 顺时针选择一次
     * @param matrix
     * @private
     */
    private rotateMatrixClockwise(matrix: ItemPosition[][]): ItemPosition[][] {
        const n = matrix.length;
        const m = matrix[0].length;
        const rotated: ItemPosition[][] = Array.from({length: m}, () => Array(n).fill(0));

        for (let i = 0; i < n; i++) {
            for (let j = 0; j < m; j++) {
                rotated[j][n - 1 - i] = matrix[i][j];
            }
        }
        return rotated;
    }


    private clickCloseGameOver() {
        this.overGame.active = false;
        this.markNode.active = false;
    }

    private printArray() {
        for (const squareArrayElement of this.squareArray) {
            for (const itemPosition of squareArrayElement) {
                console.log(`x:${itemPosition.position.x},y:${itemPosition.position.y},z:${itemPosition.position.z}, item:${itemPosition.item}`)
            }
        }
    }


    private moveUp(): boolean {
        // 左移,交换每个空格,然后看看能不能合成
        // 循环每一行
        let isMove: boolean = false;


        for (let i = 0; i < this.squareArray.length; i++) {
            // 每一列的长度
            const columnLength = this.squareArray[i].length;

            // 判断后面是否有空格
            for (let j = 0; j < columnLength; j++) {
                // 有空格，往前移动
                if (this.squareArray[j][i].position?.z === 0) {
                    for (let k = j + 1; k < columnLength; k++) {
                        if (this.squareArray[k][i].position.z !== 0) {
                            // 不是0，往前移 交换位置
                            isMove = true;
                            console.log(`交换位置：${i}-${j} 和 ${i}-${k}`)
                            this.squareArray[j][i].position.z = this.squareArray[k][i].position.z;
                            this.squareArray[j][i].item = this.squareArray[k][i].item;
                            this.squareArray[j][i].status = this.squareArray[k][i].status;
                            this.squareArray[k][i].position.z = 0;
                            this.squareArray[k][i].item = null;
                            this.squareArray[k][i].status = [];
                            this.moveAnimation(tween(this.squareArray[j][i].item), this.squareArray[j][i].position);
                            break;

                        }
                    }
                }
            }


            // 合并
            for (let j = 1; j < columnLength; j++) {
                let h = j - 1;
                if (this.squareArray[j][i].position.z != 0
                    && this.squareArray[j][i].position.z === this.squareArray[h][i].position.z) {

                    if (
                        this.isContains(this.squareArray[j][i].status, [51, 101])
                        || this.isContains(this.squareArray[h][i].status, [51, 101])
                    ) {
                        console.log("不能合并")
                        continue;
                    } else {
                        isMove = true;
                        // 前一个*2
                        let num = this.squareArray[h][i].position.z * 2;
                        this.squareArray[h][i].position.z = num;
                        // 当前归零
                        this.squareArray[j][i].position.z = 0;


                        if (this.isContains(this.squareArray[j][i].status, [151])
                            || this.isContains(this.squareArray[h][i].status, [151])) {
                            this.opponentCurrentScore += this.squareArray[h][i].position.z;
                            if (this.isContains(this.squareArray[j][i].status, [151])) {
                                let frozenItem = this.squareArray[j][i].item.getChildByName("propItem151");
                                console.log("是否存在道具", frozenItem, j, i, this.squareArray[j][i])
                                if (frozenItem) {
                                    frozenItem.parent = this.squareArray[h][i].item;
                                    frozenItem.position = v3(0, 0, 0);
                                }

                                this.addStatus(this.squareArray[h][i].status, 151, 999)
                            }

                        } else {
                            this.currentScore += this.squareArray[h][i].position.z;
                        }

                        this.addProp(this.squareArray[h][i].position.z);
                        let temp = this.squareArray[j][i].item;
                        let tempH = this.squareArray[h][i].item;
                        this.squareArray[j][i].item = null;

                        this.unfreeze(h, i);


                        this.moveAnimation(tween(temp), this.squareArray[h][i].position, () => {
                            tempH.getComponent(Item).init(num);
                            temp.destroy();
                        });

                        tween(this.squareArray[h][i].item)
                            .to(0.2, {scale: v3(1.3, 1.3, 1.3)}, {easing: "sineIn"})
                            .to(0.2, {scale: v3(1, 1, 1)}, {easing: "sineOut"})
                            .start()
                    }

                }
            }

            //合并后再次移动
            // 判断后面是否有空格
            for (let j = 0; j < columnLength; j++) {
                // 有空格，往前移动
                if (this.squareArray[j][i].position?.z === 0) {
                    for (let k = j + 1; k < columnLength; k++) {
                        if (this.squareArray[k][i].position.z !== 0) {
                            // 不是0，往前移 交换位置
                            isMove = true;
                            console.log(`交换位置：${i}-${j} 和 ${i}-${k}`)
                            this.squareArray[j][i].position.z = this.squareArray[k][i].position.z;
                            this.squareArray[j][i].item = this.squareArray[k][i].item;
                            this.squareArray[j][i].status = this.squareArray[k][i].status;
                            this.squareArray[k][i].position.z = 0;
                            this.squareArray[k][i].item = null;
                            this.squareArray[k][i].status = [];
                            this.moveAnimation(tween(this.squareArray[j][i].item), this.squareArray[j][i].position);
                            break;

                        }
                    }
                }
            }

        }
        return isMove;
    }

    private moveDown(): boolean {
        // 左移,交换每个空格,然后看看能不能合成
        // 循环每一行
        let isMove: boolean = false;


        for (let i = 0; i < this.squareArray.length; i++) {
            // 每一列的长度
            const columnLength = this.squareArray[i].length;

            // 判断后面是否有空格
            for (let j = columnLength - 1; j >= 0; j--) {
                // 有空格，往前移动
                if (this.squareArray[j][i].position?.z === 0) {
                    for (let k = j - 1; k >= 0; k--) {
                        if (this.squareArray[k][i].position.z !== 0) {
                            // 不是0，往前移 交换位置
                            isMove = true;
                            console.log(`交换位置：${i}-${j} 和 ${i}-${k}`)
                            this.squareArray[j][i].position.z = this.squareArray[k][i].position.z;
                            this.squareArray[j][i].item = this.squareArray[k][i].item;
                            this.squareArray[j][i].status = this.squareArray[k][i].status;
                            this.squareArray[k][i].position.z = 0;
                            this.squareArray[k][i].item = null;
                            this.squareArray[k][i].status = [];
                            this.moveAnimation(tween(this.squareArray[j][i].item), this.squareArray[j][i].position);
                            break;

                        }
                    }
                }
            }


            // 合并
            for (let j = columnLength - 2; j >= 0; j--) {
                let h = j + 1;
                if (this.squareArray[j][i].position.z != 0
                    && this.squareArray[j][i].position.z === this.squareArray[h][i].position.z) {

                    if (
                        this.isContains(this.squareArray[j][i].status, [101.51])
                        || this.isContains(this.squareArray[h][i].status, [101.51])
                    ) {
                        console.log("不能合并")

                        continue;
                    } else {
                        isMove = true;
                        // 前一个*2
                        let num = this.squareArray[h][i].position.z * 2;
                        this.squareArray[h][i].position.z = num;
                        // 当前归零
                        this.squareArray[j][i].position.z = 0;

                        if (this.isContains(this.squareArray[j][i].status, [151])
                            || this.isContains(this.squareArray[h][i].status, [151])) {
                            this.opponentCurrentScore += this.squareArray[h][i].position.z;
                            if (this.isContains(this.squareArray[j][i].status, [151])) {
                                let frozenItem = this.squareArray[j][i].item.getChildByName("propItem151");
                                console.log("是否存在道具", frozenItem, j, i, this.squareArray[j][i])
                                if (frozenItem) {
                                    frozenItem.parent = this.squareArray[h][i].item;
                                    frozenItem.position = v3(0, 0, 0);
                                }

                                this.addStatus(this.squareArray[h][i].status, 151, 999)
                            }

                        } else {
                            this.currentScore += this.squareArray[h][i].position.z;
                        }
                        this.addProp(this.squareArray[h][i].position.z);
                        let temp = this.squareArray[j][i].item;
                        let tempH = this.squareArray[h][i].item;
                        this.squareArray[j][i].item = null;

                        this.unfreeze(h, i);


                        this.moveAnimation(tween(temp), this.squareArray[h][i].position, () => {
                            tempH.getComponent(Item).init(num);
                            temp.destroy();
                        });

                        tween(this.squareArray[h][i].item)
                            .to(0.2, {scale: v3(1.3, 1.3, 1.3)}, {easing: "sineIn"})
                            .to(0.2, {scale: v3(1, 1, 1)}, {easing: "sineOut"})
                            .start()
                    }

                }
            }

            //合并后再次移动
            // 判断后面是否有空格
            for (let j = columnLength - 1; j >= 0; j--) {
                // 有空格，往前移动
                if (this.squareArray[j][i].position?.z === 0) {
                    for (let k = j - 1; k >= 0; k--) {
                        if (this.squareArray[k][i].position.z !== 0) {
                            // 不是0，往前移 交换位置
                            isMove = true;
                            console.log(`交换位置：${i}-${j} 和 ${i}-${k}`)
                            this.squareArray[j][i].position.z = this.squareArray[k][i].position.z;
                            this.squareArray[j][i].item = this.squareArray[k][i].item;
                            this.squareArray[j][i].status = this.squareArray[k][i].status
                            this.squareArray[k][i].position.z = 0;
                            this.squareArray[k][i].item = null;
                            this.squareArray[k][i].status = [];
                            this.moveAnimation(tween(this.squareArray[j][i].item), this.squareArray[j][i].position);
                            break;

                        }
                    }
                }
            }

        }
        return isMove;
    }

    private moveRight(): boolean {
        // 左移,交换每个空格,然后看看能不能合成
        // 循环每一行
        let isMove: boolean = false;


        for (let i = 0; i < this.squareArray.length; i++) {
            // 每一列的长度
            const columnLength = this.squareArray[i].length;

            // 判断后面是否有空格
            for (let j = columnLength - 1; j >= 0; j--) {
                // 有空格，往前移动
                if (this.squareArray[i][j].position?.z === 0) {
                    for (let k = j - 1; k >= 0; k--) {
                        if (this.squareArray[i][k].position.z !== 0) {
                            // 不是0，往前移 交换位置
                            isMove = true;
                            console.log(`交换位置：${i}-${j} 和 ${i}-${k}`)
                            this.squareArray[i][j].position.z = this.squareArray[i][k].position.z;
                            this.squareArray[i][j].item = this.squareArray[i][k].item;
                            this.squareArray[i][j].status = this.squareArray[i][k].status;
                            this.squareArray[i][k].position.z = 0;
                            this.squareArray[i][k].item = null;
                            this.squareArray[i][k].status = [];
                            this.moveAnimation(tween(this.squareArray[i][j].item), this.squareArray[i][j].position);
                            break;

                        }
                    }
                }
            }


            // 合并
            for (let j = columnLength - 2; j >= 0; j--) {
                let h = j + 1;
                if (this.squareArray[i][j].position.z != 0
                    && this.squareArray[i][j].position.z === this.squareArray[i][h].position.z) {

                    if (
                        this.isContains(this.squareArray[i][j].status, [101, 51])
                        || this.isContains(this.squareArray[i][h].status, [101, 51])
                    ) {
                        console.log("不能合并")

                        continue;
                    } else {
                        isMove = true;
                        // 前一个*2
                        let num = this.squareArray[i][h].position.z * 2;
                        this.squareArray[i][h].position.z = num;
                        // 当前归零
                        this.squareArray[i][j].position.z = 0;
                        // 被策反了，偷取一半分数
                        if (
                            this.isContains(this.squareArray[i][j].status, [151])
                            || this.isContains(this.squareArray[i][h].status, [151])) {
                            this.opponentCurrentScore += this.squareArray[i][h].position.z;

                            if (this.isContains(this.squareArray[i][j].status, [151])) {
                                let frozenItem = this.squareArray[i][j].item.getChildByName("propItem151");
                                console.log("是否存在道具", frozenItem, i, j, this.squareArray[i][j])
                                if (frozenItem) {
                                    frozenItem.parent = this.squareArray[i][h].item;
                                    frozenItem.position = v3(0, 0, 0);
                                }

                                this.addStatus(this.squareArray[i][h].status, 151, 999)
                            }
                        } else {
                            this.currentScore += this.squareArray[i][h].position.z;
                        }

                        this.addProp(this.squareArray[i][h].position.z);
                        let temp = this.squareArray[i][j].item;
                        let tempH = this.squareArray[i][h].item;
                        this.squareArray[i][j].item = null;

                        this.unfreeze(i, h);


                        this.moveAnimation(tween(temp), this.squareArray[i][h].position, () => {
                            tempH.getComponent(Item).init(num);

                            temp.destroy();
                        });

                        tween(this.squareArray[i][h].item)
                            .to(0.2, {scale: v3(1.3, 1.3, 1.3)}, {easing: "sineIn"})
                            .to(0.2, {scale: v3(1, 1, 1)}, {easing: "sineOut"})
                            .start()
                    }

                }
            }

            //合并后再次移动
            // 判断后面是否有空格
            for (let j = columnLength - 1; j >= 0; j--) {
                // 有空格，往前移动
                if (this.squareArray[i][j].position?.z === 0) {
                    for (let k = j - 1; k >= 0; k--) {
                        if (this.squareArray[i][k].position.z !== 0) {
                            // 不是0，往前移 交换位置
                            isMove = true;
                            console.log(`交换位置：${i}-${j} 和 ${i}-${k}`)
                            this.squareArray[i][j].position.z = this.squareArray[i][k].position.z;
                            this.squareArray[i][j].item = this.squareArray[i][k].item;
                            this.squareArray[i][j].status = this.squareArray[i][k].status;
                            this.squareArray[i][k].position.z = 0;
                            this.squareArray[i][k].item = null;
                            this.squareArray[i][k].status = [];
                            this.moveAnimation(tween(this.squareArray[i][j].item), this.squareArray[i][j].position);
                            break;

                        }
                    }
                }
            }

        }
        return isMove;
    }

    private moveLeft(): boolean {
        // 左移,交换每个空格,然后看看能不能合成
        // 循环每一行
        let isMove: boolean = false;


        for (let i = 0; i < this.squareArray.length; i++) {
            // 每一列的长度
            const columnLength = this.squareArray[i].length;

            // 判断后面是否有空格
            for (let j = 0; j < columnLength; j++) {
                // 有空格，往前移动
                if (this.squareArray[i][j].position?.z === 0) {
                    for (let k = j + 1; k < columnLength; k++) {
                        if (this.squareArray[i][k].position.z !== 0) {
                            // 不是0，往前移 交换位置
                            isMove = true;
                            console.log(`交换位置：${i}-${j} 和 ${i}-${k}`)
                            this.squareArray[i][j].position.z = this.squareArray[i][k].position.z;
                            this.squareArray[i][j].item = this.squareArray[i][k].item;
                            this.squareArray[i][j].status = this.squareArray[i][k].status;

                            this.squareArray[i][k].position.z = 0;
                            this.squareArray[i][k].item = null;
                            this.squareArray[i][k].status = [];
                            this.moveAnimation(tween(this.squareArray[i][j].item), this.squareArray[i][j].position);
                            break;

                        }
                    }
                }
            }


            // 合并
            for (let j = 1; j < columnLength; j++) {
                let h = j - 1;
                if (this.squareArray[i][j].position.z != 0
                    && this.squareArray[i][j].position.z === this.squareArray[i][h].position.z) {

                    // 被冻结了不合并
                    if (this.isContains(this.squareArray[i][j].status, [101, 51])
                        || this.isContains(this.squareArray[i][h].status, [101, 51])
                    ) {
                        console.log("不能合并")

                        continue;
                    } else {
                        isMove = true;
                        // 前一个*2
                        let num = this.squareArray[i][h].position.z * 2;
                        this.squareArray[i][h].position.z = num;
                        // 当前归零
                        this.squareArray[i][j].position.z = 0;
                        // 被策反了，偷取一半分数
                        if (
                            this.isContains(this.squareArray[i][j].status, [151])
                            || this.isContains(this.squareArray[i][h].status, [151])) {
                            this.opponentCurrentScore += this.squareArray[i][h].position.z;

                            if (this.isContains(this.squareArray[i][j].status, [151])) {
                                let frozenItem = this.squareArray[i][j].item.getChildByName("propItem151");
                                console.log("是否存在道具", frozenItem, i, j, this.squareArray[i][j])
                                if (frozenItem) {
                                    frozenItem.parent = this.squareArray[i][h].item;
                                    frozenItem.position = v3(0, 0, 0);
                                }

                                this.addStatus(this.squareArray[i][h].status, 151, 999)
                            }
                        } else {
                            this.currentScore += this.squareArray[i][h].position.z;
                        }

                        this.addProp(this.squareArray[i][h].position.z);
                        let temp = this.squareArray[i][j].item;
                        let tempH = this.squareArray[i][h].item;
                        this.squareArray[i][j].item = null;


                        this.unfreeze(i, h);

                        this.moveAnimation(tween(temp), this.squareArray[i][h].position, () => {
                            tempH.getComponent(Item).init(num);
                            temp.destroy();
                        });

                        tween(this.squareArray[i][h].item)
                            .to(0.2, {scale: v3(1.3, 1.3, 1.3)}, {easing: "sineIn"})
                            .to(0.2, {scale: v3(1, 1, 1)}, {easing: "sineOut"})
                            .start()
                    }


                }
            }

            //合并后再次移动
            // 判断后面是否有空格
            for (let j = 0; j < columnLength; j++) {
                // 有空格，往前移动
                if (this.squareArray[i][j].position?.z === 0) {
                    for (let k = j + 1; k < columnLength; k++) {
                        if (this.squareArray[i][k].position.z !== 0) {
                            // 不是0，往前移 交换位置
                            isMove = true;
                            console.log(`交换位置：${i}-${j} 和 ${i}-${k}`)
                            this.squareArray[i][j].position.z = this.squareArray[i][k].position.z;
                            this.squareArray[i][j].item = this.squareArray[i][k].item;
                            this.squareArray[i][j].status = this.squareArray[i][k].status;
                            this.squareArray[i][k].position.z = 0;
                            this.squareArray[i][k].item = null;
                            this.squareArray[i][k].status = [];
                            this.moveAnimation(tween(this.squareArray[i][j].item), this.squareArray[i][j].position);
                            break;

                        }
                    }
                }
            }

        }
        return isMove;
    }

    private unfreeze(i: number, j: number) {
        // 合并了，查找附近是否有被冰冻的,如果有被冰冻的-1
        let aroundSquare: ItemPosition[] = this.getAroundSquare(i, j);
        if (aroundSquare) {
            for (let k = 0; k < aroundSquare.length; k++) {
                let obj: ItemPosition = aroundSquare[k];
                // 被冰冻了，进行解冻
                let vec3StatusDTO = this.find(obj.status, 51);
                if (vec3StatusDTO) {
                    vec3StatusDTO.count--;
                    let frozenItem = obj.item.getChildByName("propItem51");
                    frozenItem.children[0].getComponent(Sprite).color = new Color(255, 255, 255, 122)

                    if (vec3StatusDTO.count <= 0) {
                        vec3StatusDTO.status = 0;
                        vec3StatusDTO.count = 0;
                        frozenItem = obj.item.getChildByName("propItem51");
                        frozenItem.destroy();
                    }
                }
            }
        }
    }

    private getAroundSquare(i: number, j: number): ItemPosition[] {
        let result: ItemPosition[] = [];
        if (this.isValidIndex(this.squareArray, i + 1, j)) {
            result.push(this.squareArray[i + 1][j]);
        }
        if (this.isValidIndex(this.squareArray, i - 1, j)) {
            result.push(this.squareArray[i - 1][j]);
        }
        if (this.isValidIndex(this.squareArray, i, j + 1)) {
            result.push(this.squareArray[i][j + 1]);
        }
        if (this.isValidIndex(this.squareArray, i, j - 1)) {
            result.push(this.squareArray[i][j - 1]);
        }
        return result;
    }

    private isValidIndex(arr: any[][], row: number, col: number): boolean {
        return arr && row >= 0 && row < arr.length && col >= 0 && col < arr[row].length;
    }


    private async init() {
        // 清除
        if (this.squereParent.children.length > 0) {
            this.squereParent.destroyAllChildren();
            this.squareArray = null;
        }

        await this.getUserInfo();
        //this.updateView();
        let squareWh1 = this.initSqureBg(this.ndLayoutComponent, this.ndParend);
        this.squareWh = squareWh1;

        let squareWh2 = this.initSqureBg(this.ndLayoutComponentTwo, this.ndParendTwo);
        this.squareWh2 = squareWh2;


        this.initSqure(this.userData.current || this.userData.before, 1);


        this.initSqure(this.userDataTwo.current || this.userDataTwo.before, 2);

        for (const squareArrayElement of this.squareArray) {
            for (const itemPosition of squareArrayElement) {
                if (itemPosition.position.z !== 0) {
                    this.addItem(itemPosition, this.ndLayoutComponent, this.squereParent, squareWh1, false);
                    if (itemPosition.status) {
                        for (const statusKey of itemPosition.status) {
                            this.addPropStatus(itemPosition, statusKey.status, itemPosition.item, squareWh1);
                        }
                    }
                }
            }
        }

        for (const squareArrayElement of this.squareTwoArray) {
            for (const itemPosition of squareArrayElement) {
                if (itemPosition.position.z !== 0) {
                    this.addItem(itemPosition, this.ndLayoutComponentTwo, this.squereParentTwo, squareWh2, false);
                    if (itemPosition.status) {
                        for (const statusKey of itemPosition.status) {
                            this.addPropStatus(itemPosition, statusKey.status, itemPosition.item, squareWh1);
                        }
                    }
                }
            }
        }

        // 初始化用户信息
        this.initGameUserInfo();
        if (!this.markNode.active) {
            this.isGame = true;
        }
    }

    private initGameUserInfo() {
        this.userName.string = this.userData.currentPlayer.wxUsername;
        this.previewUserName.string = this.userDataTwo.currentPlayer.wxUsername;
        this.userLvNode.init(this.userData.currentPlayer.game2048Level);
        this.previewUserLvNode.init(this.userDataTwo.currentPlayer.game2048Level);
        // 从url设置头像
        assetManager.loadRemote<ImageAsset>(this.userData.currentPlayer.wxHead, (err, imageAsset) => {
            const spriteFrame = new SpriteFrame();
            const texture = new Texture2D();
            texture.image = imageAsset;
            spriteFrame.texture = texture;
            this.userHead.spriteFrame = spriteFrame;
        });

        // 从url设置头像
        assetManager.loadRemote<ImageAsset>(this.userDataTwo.currentPlayer.wxHead, (err, imageAsset) => {
            const spriteFrame = new SpriteFrame();
            const texture = new Texture2D();
            texture.image = imageAsset;
            spriteFrame.texture = texture;
            this.previewUserHead.spriteFrame = spriteFrame;
        });
    }


    private initPanel() {
        this.gameMain.active = false;
        this.overGame.active = false;
    }


    private async startGame() {
        this.gameMain.active = true;
        await this.init();
        //  AudioMgr.inst.play(this.bgMusic, true);
    }


    private toLogin() {
        this.initPanel();
    }


    private async getUserInfo() {
        // 从服务器加载
        try {
            for (const player of this.roomInfo.players) {

                if (this.userInfo.id === player.currentPlayer.id) {

                    this.userData = player;


                } else {

                    this.userDataTwo = player;


                }
            }
        } catch (e) {
            console.error(e)
        } finally {
            console.log("结束")

        }

    }

    private updatePreviewView() {
        this.previewScoreLabel.string = "分数：" + this.userDataTwo.score + "";
    }

    private updateView() {
        this.scoreLabel.string = "分数：" + this.userData.score + "";
    }

    /**
     * 初始化方块
     * @private
     */


    private initSqureBg(ndLayoutComponent: LayoutComponent, ndParent: Node): number {

        // 如果已经有个bg 就不生成了
        if (ndParent.children.length > 0) {
            return;
        }

        let lv: number = parseInt(this.userData.lv);

        const trans: UITransformComponent = ndParent.getComponent(UITransformComponent);

        // (总宽-减去空隙值 )/lv
        let squureWh = (trans.contentSize.x - ((lv + 1) * ndLayoutComponent.spacingX)) / lv;
        ndLayoutComponent.cellSize = new Size(squureWh, squureWh);

        for (let i = 0; i < lv; i++) {
            for (let j = 0; j < lv; j++) {
                const prefab: Node = instantiate(this.itemBgPrefab);
                prefab.getComponent(Sprite).color = new Color(166, 227, 233,255);
                prefab.parent = ndParent;
                prefab.name = "squreBg" + i + "-" + j;
            }
        }

        return squureWh;
    }


    private copyArray()
        :
        [ItemPosition[]] {
        let newarray: [ItemPosition[]] = [[]];
        for (let i = 0; i < parseInt(this.userData.lv); i++) {
            newarray[i] = new Array(this.squareArray[i].length);
            for (let j = 0; j < parseInt(this.userData.lv); j++) {
                newarray[i][j] = new ItemPosition(v3(i, j, 0));
                if (this.squareArray[i][j].position.z != 0) {
                    newarray[i][j].position.z = this.squareArray[i][j].position.z;
                }
            }
        }
        return newarray;
    }


    private initSqure(array: [Vec3DTO[]], isMe: number) {
        if (isMe === 1) {
            this.squareArray = [new Array<ItemPosition>(array.length)];
            for (let i = 0; i < array.length; i++) {
                this.squareArray[i] = new Array(array[i].length);
                for (let j = 0; j < array[i].length; j++) {

                    this.squareArray[i][j] = new ItemPosition(v3(array[i][j].x,
                        array[i][j].y,
                        array[i][j].z));
                    this.squareArray[i][j].status = array[i][j].status;
                }
            }
        } else {
            this.squareTwoArray = [new Array<ItemPosition>(array.length)];
            for (let i = 0; i < array.length; i++) {
                this.squareTwoArray[i] = new Array(array[i].length);
                for (let j = 0; j < array[i].length; j++) {

                    this.squareTwoArray[i][j] = new ItemPosition(v3(array[i][j].x,
                        array[i][j].y,
                        array[i][j].z));
                    this.squareTwoArray[i][j].status = array[i][j].status;
                }
            }
        }

    }


    private generateRandom(score ?: number, row ?: number, column ?: number) {
        let randomNum = MathUtil.randomArray([2, 4]);
        if (score != null) {
            randomNum = score;
        }
        // 获取所有等于0的位置
        let nullArray: ItemPosition[] = [];
        for (const squareSingleArray of this.squareArray) {
            for (const square of squareSingleArray) {
                if (square.position.z === 0) {
                    nullArray.push(square);
                }
            }
        }
        let randomArray = MathUtil.randomArray(nullArray);
        if (row != null && column != null) {
            randomArray = this.squareArray[row][column];
        }
        randomArray.position.z = randomNum;
        this.addItem(randomArray, this.ndLayoutComponent, this.squereParent, this.squareWh, true);
    }


    private addItem(itemPosition
                        :
                        ItemPosition,
                    ndLayoutComponent: LayoutComponent,
                    squereParent: Node,
                    squareWh: number,
                    isAction = false
    ) {

        let itemObj: Node = instantiate(this.itemPrefab);
        itemObj.parent = squereParent;
        itemObj.name = "item-" + itemPosition.position.z;
        let itemScript = itemObj.getComponent(Item);

        itemScript.init(itemPosition.position.z);

        itemObj.getComponent(UITransformComponent).contentSize = new Size(squareWh, squareWh);
        itemObj.children[0].getComponent(UITransformComponent).contentSize = new Size(squareWh, squareWh);

        // 计算位置
        itemObj.position = this.transPosition(itemPosition.position, ndLayoutComponent, squareWh);
        itemPosition.item = itemObj;
        if (isAction) {
            itemObj.scale = v3(0, 0, 0);
            tween(itemObj).to(0.15, {scale: v3(1, 1, 1)}, {easing: "sineInOut"}).start()
        }
    }


    private transPosition(vec3: Vec3,
                          ndLayoutComponent: LayoutComponent,
                          squareWh: number
    ):
        Vec3 {
        let positionx: number = (vec3.y + 1) * ndLayoutComponent.spacingX
            + vec3.y * squareWh;

        let positionY: number = (vec3.x + 1) * ndLayoutComponent.spacingY
            + vec3.x * squareWh;
        return v3(positionx + (squareWh / 2), -positionY - (squareWh / 2), 0);
    }


    private async setScore(score: number, opponentCurrentScore: number, direction: string
    ) {
        if (score > 0) {
            AudioMgr.inst.playOneShot(this.mergeMusic);
        }
        let transArray = this.transArray();
        this.userData.before = this.userData.current;
        this.userData.current = transArray;
        this.userData.directive = direction;
        this.userData.score = this.userData.score + score;
        this.userData.opponentCurrentScore = opponentCurrentScore;
        let socketMessag: SocketMessage = new SocketMessage();
        socketMessag.event = "updateGameInfo";
        socketMessag.data = this.userData;
        WebsocketMgr.inst.sendMessage(socketMessag);
        this.updateView();
        if (opponentCurrentScore > 0) {
            this.userDataTwo.score += opponentCurrentScore;
            this.updatePreviewView();
        }
    }

    private transArray(): [Vec3DTO[]] {
        let vect3Array: [Vec3DTO[]] = [new Array<Vec3DTO>(this.squareArray.length)];
        for (let i = 0; i < this.squareArray.length; i++) {
            vect3Array[i] = new Array(this.squareArray[i].length);
            for (let j = 0; j < this.squareArray[i].length; j++) {

                vect3Array[i][j] = new Vec3DTO();
                vect3Array[i][j].x = this.squareArray[i][j].position.x
                vect3Array[i][j].y = this.squareArray[i][j].position.y
                vect3Array[i][j].z = this.squareArray[i][j].position.z
                vect3Array[i][j].status = this.squareArray[i][j].status
            }
        }
        return vect3Array;
    }


    private moveAnimation(itemObj: Tween<Node>,
                          newPosition: Vec3, call ?: () => void
    ):
        Tween<Node> {
        let nodeTween = itemObj.to(0.08, {position: this.transPosition(newPosition, this.ndLayoutComponent, this.squareWh)}, {easing: "linear"});
        if (call != null
        ) {
            nodeTween.call(call);
        }
        itemObj.start();
        return itemObj;
    }


    public clickHome() {
        if (this.roomInfo.status === 1) {
            Modal.Instance.show("提示", "退出游戏会被判负哦!", () => {
                let socketMessag: SocketMessage = new SocketMessage();
                socketMessag.event = "exitRoom";
                socketMessag.data = "manyGame2048"
                WebsocketMgr.inst.sendMessage(socketMessag);
                sys.localStorage.removeItem("roomInfo");
                this.deSubscription();
                director.loadScene("home");
            });
        } else {
            let socketMessag: SocketMessage = new SocketMessage();
            socketMessag.event = "exitRoom";
            socketMessag.data = "manyGame2048"
            WebsocketMgr.inst.sendMessage(socketMessag);

            sys.localStorage.removeItem("roomInfo");
            this.deSubscription();
            director.loadScene("home");
        }

    }

    /**
     * 打开游戏说明
     * @private
     */
    private openGameDesc() {
        Modal.Instance.show("2048游戏说明", `1.棋盘初始化随机出现两个数字，出现的数字仅可能为2或4。
2.玩家上下左右四个方向滑动,若有空格或可合并数字视为有效移动。
3.有效移动后会增加得分,并生成随机数字2或4。
4.棋盘被数字填满，无法进行有效移动，判负，游戏结束!
        `);
    }

    subscription() {
        console.log("订阅")
        WebsocketMgr.inst.initSocket();
        WebsocketMgr.inst.socketLogic.set(this.getPatch(), this);
        WebsocketMgr.inst.officeMessage.set(this, this.officeMessage);
        WebsocketMgr.inst.opponentOfficeMessage.set(this, this.opponentOffice);
        WebsocketMgr.inst.reconnectSuccessMessage.set(this, this.reconnectSuccess);
        WebsocketMgr.inst.opponentReconnectSuccessMessage.set(this, this.opponentReconnectSuccess);
    }

    accept(message: SocketMessage) {
        let events = message.event.split('/');
        // 对手移动
        if (events[1] === "rivalMove") {
            this.rivalMove(message);
            return;
        }
        // 胜利
        if (events[1] === "win") {
            this.win(message);
            return;
        }
        // 匹配成功
        if (events[1] === "matchSuccess") {
            this.matchSuccess(message);
            return;
        }
        // 对手使用道具
        if (events[1] === "opponentUseProp") {
            this.opponentUseProp(message);
            return;
        } // 使用道具成功回应
        if (events[1] === "enemyPropSuccess") {
            this.enemyPropSuccess(message);
            return;
        }
        // 对手离开
        if (events[1] === "otherExitRoom") {
            this.otherExitRoom(message);
            return;
        }
        if (events[1] === "otherUpdatePlayerStatus") {
            this.otherPrepare(message);
            return;
        }
        if (events[1] === "StartGame") {
            this.socketStartGame(message);
            return;
        }
    }


    getPatch(): string {
        return "manyGame2048";
    }

    timeoutInterval: number;

    /**
     * 对手移动更新
     * @param message
     * @private
     */
    private rivalMove(message: SocketMessage) {
        this.userDataTwo = message.data;
        this.updatePreviewView();
        if (this.userDataTwo.opponentCurrentScore > 0) {
            this.userData.score += this.userDataTwo.opponentCurrentScore;
            this.updateView();
        }
        /*  if (this.timeoutInterval) {
              return;
          }*/
        this.timeoutInterval = setTimeout(() => {
            this.timeoutInterval = null;

            this.updatePreviewSquare(this.userDataTwo.current);

            /*  for (const squareArrayElement of this.squareTwoArray) {
                  for (const itemPosition of squareArrayElement) {
                      if (itemPosition.position.z !== 0) {
                          this.addItem(itemPosition, this.ndLayoutComponentTwo, this.squereParentTwo, this.squareWh2, false);
                          if (itemPosition.status) {
                              for (const status of itemPosition.status) {
                                  this.addPropStatus(itemPosition, status.status, itemPosition.item, this.squareWh2);
                              }
                          }
                      }
                  }
              }*/
        }, 1)

    }

    private updatePreviewSquare(current: [Vec3DTO[]]) {
        if (this.squereParentTwo.children.length > 0) {
            this.squereParentTwo.destroyAllChildren();
            this.squareTwoArray = null;
        }
        this.initSqure(current, 2);
        for (const squareArrayElement of this.squareTwoArray) {
            for (const itemPosition of squareArrayElement) {
                if (itemPosition.position.z !== 0) {
                    this.addItem(itemPosition, this.ndLayoutComponentTwo, this.squereParentTwo, this.squareWh2, false);
                    for (const status of itemPosition.status) {
                        this.addPropStatus(itemPosition, status.status, itemPosition.item, this.squareWh2);
                    }
                }
            }
        }

    }


    officeTimeOut: number;
    officeTimeOutTwo: number;

    /**
     * 设置离线显示
     * @param type 1:对方离线 0:自己离线
     * @private
     */
    private setOfficeShow(type) {

        let textComp;
        if (type === 0) {
            this.officeTimeOut && clearInterval(this.officeTimeOut);
            this.office.active = true;
            textComp = this.office.children[0].getComponent(Label);
            textComp.string = "重连中.";
            this.officeTimeOut = setInterval(() => {
                // 这里的 this 指向 component
                if (textComp.string === "重连中...") {
                    textComp.string = "重连中."
                    return;
                }
                textComp.string += ".";
            }, 1000)
        } else {
            this.previewOffice.active = true;
            textComp = this.previewOffice.children[0].getComponent(Label);
            this.officeTimeOutTwo && clearInterval(this.officeTimeOutTwo);
            textComp.string = "重连中.";
            this.officeTimeOutTwo = setInterval(() => {
                // 这里的 this 指向 component
                if (textComp.string === "重连中...") {
                    textComp.string = "重连中."
                    return;
                }
                textComp.string += ".";
            }, 1000)
        }
    }

    private officeMessage() {
        console.log("接收到离线消息", this)
        this.setOfficeShow(0);
    }

    private opponentOffice() {
        console.log("接收到对手离线消息", this)
        console.log("接收到对手离线消息", this.node.name)
        this.setOfficeShow(1);
    }

    private reconnectSuccess() {
        console.log("重连成功")
        console.log("1", WebsocketMgr.inst.opponentOfficeMessage)
        this.officeTimeOut && clearInterval(this.officeTimeOut);
        this.office.active = false;
    }


    private opponentReconnectSuccess() {
        console.log("重连成功")
        this.officeTimeOutTwo && clearInterval(this.officeTimeOutTwo);
        this.previewOffice.active = false;
    }

    private getRemaining(date: string) {
        // 当前时间
        const now = new Date();
        let date1 = DateTimeUtil.parseDate(date);
        // 计算时间差（单位：毫秒）
        const diffInMilliseconds = date1.getTime() - now.getTime();

        // 转换为秒
        const diffInSeconds = Math.ceil(diffInMilliseconds / 1000);

        // 如果时间差为负数，表示目标时间已经过去
        return diffInSeconds < 0 ? 0 : diffInSeconds;
    }

    private win(message: SocketMessage) {
        this.isGameOver = true;
        let labelText: Node = this.overGame.getChildByPath("win/Label");
        this.remainStartInterval && clearInterval(this.remainStartInterval);


        this.squareArray = null;
        this.overGame.active = true;
        this.markNode.active = true;
        this.roomInfo.status = 2;
        if (message.data == 1) {
            labelText.getComponent(Label).string = `胜利`;

        } else {
            labelText.getComponent(Label).string = `失败`;
        }
        this.setShowStar(message.data == 1);

    }

    private async gameOver() {
        //  this.roomInfo.gameOver = true;
        this.isGameOver = true;
        this.squareArray = null;

        this.roomInfo.status = 2;
        this.remainStartInterval && clearInterval(this.remainStartInterval);
        let socketMessag: SocketMessage = new SocketMessage();
        socketMessag.event = "failure";
        WebsocketMgr.inst.sendMessage(socketMessag);
        let labelText: Node = this.overGame.getChildByPath("win/Label");
        this.overGame.active = true;
        this.markNode.active = true;
        labelText.getComponent(Label).string = `失败`;
        this.setShowStar(false);
    }

    /**
     *
     * @param win 1胜利 2：失败
     * @private
     */
    private setShowStar(win: boolean) {
        console.log("设置显示星星")
        let levelEnumInfoElement: LevelInfo = levelEnumInfo[this.userInfo.game2048Level];
        this.winUserLvNode.init(this.userInfo.game2048Level);
        // 总共星星数量
        let starCount = levelEnumInfoElement.star;


        let star: Stat[] = [];
        // 把已有所有的星星复制上去
        for (let i = 0; i < starCount; i++) {
            let starNode = instantiate(this.starPrefab);
            starNode.parent = this.starIContail;
            if (this.userInfo.star > i) {
                // 已有星星
                starNode.getComponent(Stat).init(this.star);
            } else {
                // 其他是空格
                starNode.getComponent(Stat).init(this.starNull);
            }
            star.push(starNode.getComponent(Stat));
        }
        this.starIContail.getComponent(WidgetComponent).bottom = -90;
        console.log("当前星星个数", this.userInfo.star)
        console.log("星星个数：", star.length)
        let uiCallBack: () => void;

        // 首先计算逻辑
        if (win) {
            if (this.userInfo.star + 1 <= starCount) {
                console.log("加个星星")
                // 小于等于最大星星数量，加上星星
                this.userInfo.star += 1;
                uiCallBack = () => {
                    star[this.userInfo.star - 1].init(this.star);
                }

            } else {
                console.log("突破下个段位")
                const currentLevel = Game2048LevelEnum[this.userInfo.game2048Level as keyof typeof Game2048LevelEnum];
                let nextLevel = getNextLevel(currentLevel);

                if (nextLevel) {
                    this.userInfo.game2048Level = nextLevel;
                    this.userInfo.star = 0;
                    uiCallBack = () => {
                        this.winUserLvNode.init(this.userInfo.game2048Level);
                        for (const starElement of star) {
                            starElement.init(this.starNull);
                        }
                    }
                }

            }
        } else {
            if (this.userInfo.star - 1 >= 0) {
                console.log("减个星星")

                // 星星减少一颗
                this.userInfo.star -= 1;
                uiCallBack = () => {
                    star[this.userInfo.star].init(this.starNull);
                }
            } else {
                console.log("段位下降 真残忍啊")

                const currentLevel = Game2048LevelEnum[this.userInfo.game2048Level as keyof typeof Game2048LevelEnum];
                let beforeLevel = getBeforeLevel(currentLevel);
                if (beforeLevel) {
                    levelEnumInfoElement = levelEnumInfo[beforeLevel];
                    this.userInfo.star = levelEnumInfoElement.star;
                    this.userInfo.game2048Level = beforeLevel;
                    uiCallBack = () => {
                        this.winUserLvNode.init(this.userInfo.game2048Level);

                        for (const starElement of star) {
                            starElement.init(this.star);
                        }
                    }

                }

            }
        }

        // 存入逻辑
        sys.localStorage.setItem("userInfo", JSON.stringify(this.userInfo));


        setTimeout(() => {
            uiCallBack && uiCallBack();
            this.starIContail.getComponent(WidgetComponent).bottom = -90;
        }, 800)
    }

    private match() {
        // 匹配的文案
        let socketMessag: SocketMessage = new SocketMessage();
        socketMessag.event = "match2048";
        WebsocketMgr.inst.sendMessage(socketMessag);

        this.gamePending.active = true;
        this.gamePendingText.string = "匹配中.";
        this.schedule(this.gamePendingingScedule, 1);

        this.overGame.active = false;
    }

    private prepare() {
        console.log("已准备")
        let socketMessag: SocketMessage = new SocketMessage();
        this.userData.status = 1;
        socketMessag.event = "updatePlayerStatus";
        socketMessag.data = this.userData.status;
        socketMessag.message = "manyGame2048";
        WebsocketMgr.inst.sendMessage(socketMessag);
        this.userStatusLabel.children[0].getComponent(Label).string = "已准备";
        this.userStatusLabel.active = true;
        this.overGame.active = false;
        this.markNode.active = false;

    }

    private otherPrepare(message: SocketMessage) {
        this.userDataTwo.status = 1;
        this.userStatusTwoLabel.children[0].getComponent(Label).string = "已准备";
        this.userStatusTwoLabel.active = true;

    }

    private gamePendingingScedule() {
        // 这里的 this 指向 component
        if (this.gamePendingText.string === "匹配中...") {
            this.gamePendingText.string = "匹配中."
            return;
        }
        this.gamePendingText.string += ".";
    }


    private matchSuccess(message: SocketMessage) {
        console.log("匹配成功");
        sys.localStorage.setItem("roofInfo", JSON.stringify(message.data));
        this.deSubscription();
        director.loadScene("gameMany2048")
    }

    deSubscription() {
        console.log("取消订阅消息")
        WebsocketMgr.inst.socketLogic.delete(this.getPatch());
        WebsocketMgr.inst.officeMessage.delete(this);
        WebsocketMgr.inst.opponentOfficeMessage.delete(this);
        WebsocketMgr.inst.reconnectSuccessMessage.delete(this);
        WebsocketMgr.inst.opponentReconnectSuccessMessage.delete(this);
    }

    /**
     * 增加道具
     * @param num
     */
    addProp(num: number) {
        let type: number = this.getProp(num);
        if (type == null || type == 0) {
            return;
        }

        console.log("获得道具", type)
        let props: Prop = new Prop();

        props.type = type;
        props.id = Date.now() + "";


        if (!this.userData.props) {
            this.userData.props = [];
        }
        if (this.userData.props.length >= 9) {
            console.log("道具足够不生成道具")
            return;
        }
        this.userData.props.push(props)
        let socketMessag: SocketMessage = new SocketMessage();
        socketMessag.event = "addProp";
        socketMessag.data = props.id + "-" + props.type;
        WebsocketMgr.inst.sendMessage(socketMessag);

        this.addPropPanel(props);
    }

    /**
     * 一星道具,炸弹,冻结,迷雾,护盾
     * 二星道具,镜像反转,终局赌注
     * 三星道具,方块吸取,数字诅咒
     * 获取道具,随机生成
     * @param num
     */
    getProp(num: number): number {
        if (num >= 32 && num < 128) {
            // 生成一星道具
            let number = MathUtil.randomMax(100);
            if (number < 30 * (num / 32)) {
                return MathUtil.getRandomEnumValue(PropTypeOneEnum).valueOf() + (50 * 1);

            }
        }
        if (num >= 128 && num < 256) {
            // 生成二星道具
            let number = MathUtil.randomMax(100);
            if (number < 30 * (num / 128)) {
                return MathUtil.getRandomEnumValue(PropTypeTwoEnum).valueOf() + (50 * 2);
            } else {
                number = MathUtil.randomMax(100);
                if (number < 60) {
                    return MathUtil.getRandomEnumValue(PropTypeOneEnum).valueOf() + (50 * 1);
                }
            }
        }

        if (num >= 256) {
            // 生成三星道具
            let number = MathUtil.randomMax(100);
            if (number < 30 * (num / 256)) {
                return MathUtil.getRandomEnumValue(PropTypeThreeEnum).valueOf() + (50 * 3);

            } else {
                number = MathUtil.randomMax(100);
                if (number < 60) {
                    return MathUtil.getRandomEnumValue(PropTypeTwoEnum).valueOf() + (50 * 2);
                } else {
                    number = MathUtil.randomMax(100);
                    if (number < 60) {
                        return MathUtil.getRandomEnumValue(PropTypeOneEnum).valueOf() + (50 * 1);
                    }
                }

            }
        }
        return null;
    }

    public downProp() {

        for (let key in PropTypeOneEnum) {
            // 过滤掉数字索引对应的属性
            if (isNaN(Number(key))) {
                const value = PropTypeOneEnum[key as keyof typeof PropTypeOneEnum];
                // 从url下载道具
                assetManager.loadRemote<ImageAsset>("https://hq-store.oss-cn-shanghai.aliyuncs.com/prop/" + (50 + value + 1) + ".png?t=" + new Date(),
                    (err, imageAsset) => {
                        const spriteFrame = new SpriteFrame();
                        const texture = new Texture2D();
                        texture.image = imageAsset;
                        spriteFrame.texture = texture;
                        this.propSpriteMap.set(value + 50, spriteFrame)
                    });
            }
        }

        for (let key in PropTypeTwoEnum) {
            // 过滤掉数字索引对应的属性
            if (isNaN(Number(key))) {
                const value = PropTypeTwoEnum[key as keyof typeof PropTypeTwoEnum];
                // 从url下载道具
                assetManager.loadRemote<ImageAsset>("https://hq-store.oss-cn-shanghai.aliyuncs.com/prop/" + (100 + value + 1) + ".png", (err, imageAsset) => {
                    const spriteFrame = new SpriteFrame();
                    const texture = new Texture2D();
                    texture.image = imageAsset;
                    spriteFrame.texture = texture;
                    this.propSpriteMap.set(value + 100, spriteFrame)
                });
            }
        }


        for (let key in PropTypeThreeEnum) {
            // 过滤掉数字索引对应的属性
            if (isNaN(Number(key))) {
                const value = PropTypeThreeEnum[key as keyof typeof PropTypeThreeEnum];
                // 从url下载道具
                assetManager.loadRemote<ImageAsset>("https://hq-store.oss-cn-shanghai.aliyuncs.com/prop/" + (150 + value + 1) + ".png", (err, imageAsset) => {
                    const spriteFrame = new SpriteFrame();
                    const texture = new Texture2D();
                    texture.image = imageAsset;
                    spriteFrame.texture = texture;
                    this.propSpriteMap.set(value + 150, spriteFrame)
                });
            }
        }
    }


    private initProp() {
        this.propPanel.destroyAllChildren();
        if (!this.userData.props) {
            return;
        }
        for (let i = 0; i < this.userData.props.length; i++) {
            if (this.userData.props[i].type != 0) {
                this.addPropPanel(this.userData.props[i]);
            }
        }
    }

    private addPropPanel(prop: Prop) {
        console.log("初始化道具", prop)
        const prefab: Node = instantiate(this.propItem);
        prefab.parent = this.propPanel;
        prefab.name = "propItem" + prop.type;
        let info: DirectionInfo = propTypeInfo[prop.type];
        let spriteFrame = this.propSpriteMap.get(prop.type);

        if (!spriteFrame) {

            assetManager.loadRemote<ImageAsset>("https://hq-store.oss-cn-shanghai.aliyuncs.com/prop/" + (prop.type + 1) + ".png", (err, imageAsset) => {
                spriteFrame = new SpriteFrame();
                const texture = new Texture2D();
                texture.image = imageAsset;
                spriteFrame.texture = texture;
                prefab.getComponent(PropItemScript).init(
                    spriteFrame,
                    info.title,
                    info.desc,
                    prop.type,
                    prop.id,
                    this);
            });
        } else {
            prefab.getComponent(PropItemScript).init(
                spriteFrame,
                info.title,
                info.desc,
                prop.type,
                prop.id,
                this);
        }


    }

    useProp(obj: PropItemScript) {
        /*obj.node.parent = this.canvas;
        this.canvas.getComponent(Canvas);


        obj.node.position = v3(this.chessboard.position.x + this.chessboard.parent.position.x,
            this.chessboard.position.y + this.chessboard.parent.position.y);


        let targetPosition = v3(this.previewChessboard.position.x ,
            this.previewChessboard.position.y );
        tween(obj.node)
              .to(0.4, {position: targetPosition}, {easing: "linear"})
              .start()*/
        try {
            if (this.currentPropItem) {
                console.log("当前存在道具", this.currentPropItem)
                return;
            }
            this.currentPropItem = obj;

            // 查找自己用的道具
            let prop: Prop;
            for (let i = 0; i < this.userData.props.length; i++) {
                let propItem: Prop = this.userData.props[i];
                if (propItem.id === obj.id) {
                    prop = propItem;
                }
            }
            console.log("是否找到道具", prop)
            if (!prop) {
                console.log("没有找到道具，销毁")
                this.currentPropItem = null;
                obj.node.destroy();
                return;
            }


            let message: SocketMessage = new SocketMessage();
            message.event = "useProp";
            let useProp: UsePropDTO = new UsePropDTO();
            useProp.prop = prop;
            let itemPosition: ItemPosition;
            // 幸运方块
            if (prop.type === 150) {
                itemPosition = this.randomSquare(1);
                if (itemPosition) {
                    useProp.selectMePosition = [itemPosition.position];
                }
            }

            message.data = useProp;


            WebsocketMgr.inst.sendMessage(message);

            // 合成
            if (prop.type === 150 && useProp.selectMePosition) {
                let score = this.mergeSquare2(this.squareArray, this.userData, itemPosition.position.x, itemPosition.position.y);
                //计算积分
                this.userData.score = this.userData.score + score;
                this.updateView();
            } else if (prop.type === 53) {
                // 驱散异常
                /*  let propPrefab: Node = this.addPropStatus(
                      null,
                      prop.type,
                      this.propLayout,
                      this.squareWh2 * 4
                  );
                  propPrefab.children[0].getComponent(Sprite).color = new Color(48, 240, 201, 100);*/
                // 清除所有异常
                for (const squareRowArr of this.squareArray) {
                    for (const itemPosition1 of squareRowArr) {
                        itemPosition1.status = [];
                        //propItem
                        if (itemPosition1.item) {
                            // 下面道具销毁
                            for (const child of itemPosition1.item.children) {
                                if (child.name.startsWith("propItem")) {
                                    child.destroy();
                                }
                            }
                        }
                    }
                }

                /* setTimeout(() => {
                     propPrefab.destroy();
                 }, 300)*/
            }
        } catch (e) {
            console.error(e);
            this.currentPropItem = null;
        }

    }

    private mergeSquare2(squareArray: ItemPosition [][], clientInfoDTO: ClientInfoDTO, i: number, j: number): number {
        // 数字合成
        let element = squareArray[i][j];
        element.position.z = element.position.z * 2
        let current = clientInfoDTO.current || clientInfoDTO.before;
        current[i][j].z = element.position.z;
        tween(element.item)
            .to(0.2, {scale: v3(1.3, 1.3, 1.3)}, {easing: "sineIn"})
            .to(0.2, {scale: v3(1, 1, 1)}, {easing: "sineOut"})
            .call(() => {
                element.item
                    .getComponent(Item)
                    .init(element.position.z);
            })
            .start();
        return element.position.z;
    }

    private opponentUseProp(message: SocketMessage) {
        let usePropDTO: UsePropDTO = message.data as UsePropDTO;
        this.opponentProp.push(usePropDTO);
    }


    private addPropStatus(itemPosition: ItemPosition,
                          type: number,
                          propLayout: Node,
                          squareWh: number,
                          prefab?: Node): Node {
        try {
            if (type == 0) {
                return;
            }
            if (prefab == null) {
                prefab = instantiate(this.propItem);
                prefab.parent = propLayout;
                prefab.name = "propItem" + type;
                let info: DirectionInfo = propTypeInfo[type];
                let spriteFrame = this.propSpriteMap.get(type);

                if (!spriteFrame) {
                    assetManager.loadRemote<ImageAsset>("https://hq-store.oss-cn-shanghai.aliyuncs.com/prop/" + (type + 1) + ".png", (err, imageAsset) => {
                        spriteFrame = new SpriteFrame();
                        const texture = new Texture2D();
                        texture.image = imageAsset;
                        spriteFrame.texture = texture;
                        prefab.getComponent(PropItemScript).init(
                            spriteFrame,
                            info.title,
                            info.desc,
                            type,
                            "-1",
                            this);
                    });
                } else {
                    prefab.getComponent(PropItemScript).init(
                        spriteFrame,
                        info.title,
                        info.desc,
                        type,
                        "-1",
                        this);
                }


            }

            let canvasLocalPos = v3(0, 0, 0);
            if (itemPosition) {
                let item = itemPosition.item;
                let bWorldPos = item.parent.getComponent(UITransform).convertToWorldSpaceAR(item.position);
                canvasLocalPos = propLayout.getComponent(UITransform)!.convertToNodeSpaceAR(bWorldPos);
            }

            prefab.getComponent(UITransformComponent).contentSize = new Size(squareWh, squareWh);
            prefab.children[0].getComponent(UITransformComponent).contentSize = new Size(squareWh, squareWh);
            prefab.parent = propLayout;
            prefab.position = canvasLocalPos;
            prefab.children[1].active = false;
            prefab.children[0].scale = v3(1, 1, 1);
            return prefab;
        } catch (e) {
            console.log("增加异常道具", e)
        }


    }

    private addStatus(statusArr: Vec3StatusDTO[], status: number, count: number) {
        if (statusArr == null) {
            statusArr = [];
        }
        let vec3: Vec3StatusDTO = new Vec3StatusDTO();
        vec3.status = status;
        vec3.count = count;
        statusArr.push(vec3);
    }

    private isContains(statusArr: Vec3StatusDTO[], status: number[]): boolean {
        if (!statusArr) {
            return false;
        }
        for (let i = 0; i < statusArr.length; i++) {
            let statusObj: Vec3StatusDTO = statusArr[i];
            if (status.includes(statusObj.status)) {
                return true;
            }
        }
        return false;
    }

    private find(statusArr: Vec3StatusDTO[], status: number): Vec3StatusDTO {
        if (!statusArr) {
            return null;
        }
        for (let i = 0; i < statusArr.length; i++) {
            let statusObj: Vec3StatusDTO = statusArr[i];
            if (statusObj.status == status) {
                return statusObj;
            }
        }
        return null;
    }

    showPropDesc(param: PropItemScript) {

        let bWorldPos = param.node.parent.getComponent(UITransform).convertToWorldSpaceAR(param.node.position);
        const pos = this.canvas.getComponent(UITransform)!.convertToNodeSpaceAR(bWorldPos);

        this.propDescPanel.children[0].getComponent(Label).string = param.titile;
        this.propDescPanel.children[1].getComponent(Label).string = param.body;
        this.propDescPanel.position = v3(pos.x - 100, pos.y + 200, 0);
        this.propDescPanel.active = true;
    }

    closePropDesc() {
        this.propDescPanel.active = false;
    }

    private cancelMatch() {
        this.unschedule(this.gamePendingingScedule);
        this.gamePending.active = false;
        this.markNode.active = false;
        let socketMessag: SocketMessage = new SocketMessage();
        socketMessag.event = "cancelMatch";
        WebsocketMgr.inst.sendMessage(socketMessag);
    }

    destroy(): boolean {
        if (this.starInterval)
            clearInterval(this.starInterval);
        if (this.remainStartInterval)
            clearInterval(this.remainStartInterval);
        return true;
    }

    private otherExitRoom(message: SocketMessage) {
        this.userStatusTwoLabel.children[0].getComponent(Label).string = "已离开";
        this.userStatusTwoLabel.active = true;
        this.userStatusTwoLabel.getComponent(Sprite).color = new Color(38, 38, 38, 255);
    }

    private socketStartGame(message: SocketMessage) {
        sys.localStorage.setItem("roofInfo", JSON.stringify(message.data));
        this.deSubscription();
        director.loadScene("gameMany2048")
    }

    private setColor(remaining: number) {
        let meSquareNode: Node[] = this.squereParent.children;
        let previewSquareNode: Node[] = this.squereParent.children;
        let bgColor: string = this.getBackgroundColor(remaining);
        this.bgPalette.colorLT = new Color(bgColor);
        this.bgPalette.colorRT = new Color(bgColor);
        this.bgPalette.colorLB = new Color(bgColor);
        this.bgPalette.colorRB = new Color(bgColor);

    }

    public getBackgroundColor(remaining: number): string {
        if (remaining > 60) {
            return ColorUtil.hslToHex(120, 50, 90);
        }
        if (remaining > 30) {
            return ColorUtil.hslToHex(60, 50, 75);
        }
        if (remaining > 10) {
            return ColorUtil.hslToHex(30, 50, 65);
        }
        if (remaining >= 0) {
            return ColorUtil.hslToHex(0, 50, 60);
        }
        return ColorUtil.hslToHex(0, 50, 60);
    }


}